package com.gopay.bis.manager.bank;

import com.gopay.common.cache.client.RedisClient;
import com.gopay.common.constants.bank.BankConstants;
import com.gopay.common.constants.bank.BankOfAffiliationConstants;
import com.gopay.common.constants.bank.BrovisionsConstants;
import com.gopay.common.constants.bank.NuccConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseHeaderMessage;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseMessage;
import com.gopay.common.domain.bank.nucc.common.serial.req.NuccSerialBodyReq;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.NuccCommonService;
import java.security.SecureRandom;
import java.util.Map;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;

/**
 * 网联流水号获取
 * Created by zhoutong on 2018/1/16.
 */
public class NuccSerialManager {
    private static Logger logger = LoggerFactory.getLogger(NuccSerialManager.class);

    @Resource(name = "nuccConfig")
    private Map<String, String> nuccConfig;

    @Resource(name = "nuccUrlConfig")
    private Map<String, String> nuccUrlConfig;

    @Resource(name="nuccCommonServiceClient")
    private NuccCommonService nuccCommonServiceClient;

    /**
     * 定时获取流水号规则放置redis
     * @throws GopayException
     * @author zhoutong
     */
    @Scheduled(fixedRate = 3600000)
    public void getFlowIdRule()throws GopayException {
        if("off".equals(nuccConfig.get("NUCC.FLOWIDRULE.SWITCH"))){
            return;
        }
        logger.info("=======获取网联交易流水号规则");
        //组装报文
        NuccBaseMessage message =this.buildGetFlowIdRule();
        //随机获取url
        String flowIdruleUrl = nuccConfig.get("NUCC.FLOWIDRULE.URL");

        String[] urls = flowIdruleUrl.split(",");
        SecureRandom secureRandom = new SecureRandom();
        String url = urls[secureRandom.nextInt(urls.length)];
        message.setPayUrl(url);
        //发送交易
        nuccCommonServiceClient.serialApply(message);
    }

    /**
     * 构建获取交易流水号报文
     * @return
     * @throws GopayException
     */
    private NuccBaseMessage buildGetFlowIdRule() throws GopayException {
        NuccBaseMessage message = new NuccBaseMessage();
        NuccBaseHeaderMessage header = new NuccBaseHeaderMessage();
        try{
            header.setSndDt(DateUtils.now2string("yyyy-MM-dd HH:mm:ss").replace(" ", "T"));
            //报文类型代码
            header.setMsgTp(nuccConfig.get("NUCC.EXPAY.GETFLOWID.MSGTP"));
            //发起方所属机构标示
            header.setIssrId(nuccConfig.get("GOPAY.ISSRID"));
            //报文方向  11-支付机构到平台
            header.setDrctn(nuccConfig.get("NUCC.EXPAY.DRCTN"));
            //签名证书序列号
            header.setSignSN(nuccConfig.get("NUCC.EXPAY.SIGNSN"));

            NuccSerialBodyReq body = new NuccSerialBodyReq();
            //发起方所属机构标示
            body.setInstgId(nuccConfig.get("GOPAY.ISSRID"));
            message.setMsgHeader(header);
            message.setMsgBody(body);
        }catch(Exception e){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6077,e);
        }
        return message;
    }

    /**
     * 从缓存获取规则组装流水号
     * @param base
     * @param payMark
     * @param flag
     * @return
     * @throws GopayException
     */
    public void generateFlowIdBySerial(BaseMessage base, boolean payMark, String flag)  throws GopayException {
        try {
            //如果缓存中没有流水号规则缓存则主动调用接口
            if (!RedisClient.exists(NuccConstants.NUCC_SERIAL_REDIS_KEY)) {
                this.getFlowIdRule();
            }
            //主动调用接口后还是没有则报错
            if (!RedisClient.exists(NuccConstants.NUCC_SERIAL_REDIS_KEY)) {
                //抛出缓存中不存在流水号异常
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6121);
            }
            //从缓存中获取规则组装流水号
            Map<String, String> map = RedisClient.hgetAll(NuccConstants.NUCC_SERIAL_REDIS_KEY);
            String serial = map.get(NuccConstants.NUCC_SERIAL_REDIS_FIELD + new SecureRandom().nextInt(map.size()));
            //交易流水号
            if(payMark){
                base.setBankOrderId(DateUtils.now2string("yyyyMMdd") + base.getOrderId() + flag + serial);
            }else{
                base.setBankOrderId(DateUtils.now2string("yyyyMMddHHmmssSSS") + (int)((Math.random()*9+1)*1000000) + flag + serial);
            }
            //通过规则获取url
            String url = this.getUrlBySerial(serial);
            base.setPayUrl(url);
        }catch (Exception e){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6121,e.getMessage());
        }
    }

    /**
     * 通过流水号规则获取url
     * @param serial
     * @return
     */
    public String getUrlBySerial(String serial){
        //获取流水号规则前两位
        String idc = serial.substring(0,2);
        //从map中获取idc对应的url
        String url = nuccUrlConfig.get(idc);
        return url;
    }
    
    /**
     * 获取备付金账户信息
     * @param bankCode
     * @return
     */
    public String[] getAccountInfo(String bankCode){
    	String accountInfo[] = new String[2] ;
    	String aInfo = BrovisionsConstants.getAccountInfo(bankCode);
    	//获取各行备付金账户信息，如果有些银行没有备付金账户信息，则使用工行备付金账户信息
    	if(aInfo!=null){
    		String[] split = aInfo.split("=");
    		accountInfo[0]=split[0];
    		accountInfo[1]=BankOfAffiliationConstants.getAffiliation(bankCode);
    	}else{
    		String icbcInfo = BrovisionsConstants.getAccountInfo(BankConstants.BANK_LOGO_ICBC);
    		String[] split = icbcInfo.split("=");
    		accountInfo[0]=split[0];
    		accountInfo[1]=BankOfAffiliationConstants.getAffiliation(BankConstants.BANK_LOGO_ICBC);
    	}
		return accountInfo;
    	
    }


    public Map<String, String> getNuccConfig() {
        return nuccConfig;
    }

    public void setNuccConfig(Map<String, String> nuccConfig) {
        this.nuccConfig = nuccConfig;
    }

    public Map<String, String> getNuccUrlConfig() {
        return nuccUrlConfig;
    }

    public void setNuccUrlConfig(Map<String, String> nuccUrlConfig) {
        this.nuccUrlConfig = nuccUrlConfig;
    }

    public NuccCommonService getNuccCommonServiceClient() {
        return nuccCommonServiceClient;
    }

    public void setNuccCommonServiceClient(NuccCommonService nuccCommonServiceClient) {
        this.nuccCommonServiceClient = nuccCommonServiceClient;
    }
}
